'''This module is used for implement sipc communication'''

from uuid import uuid1
from hashlib import md5,sha1
import binascii
import re
from util import d_print, http_send

FetionSIPP= "SIPP"

FetionLoginXML = """<args><device type="PC" version="0" client-version="3.2.0540" /><caps value="simple-im;im-session;temp-group;personal-group" /><events value="contact;permission;system-message;personal-group" /><user-info attributes="all" /><presence><basic value="400" desc="" /></presence></args>"""

class SIPC_V2:
	global FetionSIPP
	global FetionLoginXML
	ver = "SIP-C/2.0" 
	ID = 1
	TAG = 'SPIC_V2'
	STOCK_BUDDY_LIST = "4"
	
	def __init__(self, sid, domain, passwd, http_tunnel, ssic, sipc_proxy):
		self.__sid = sid
		self.__domain = domain
		self.__passwd = passwd
		self.__seq = 1 #cmd squence
		self.__sipc_proxy = sipc_proxy
		self.__http_tunnel = http_tunnel
		self.__ssic = ssic
		self.__guid = str(uuid1())
		self.__exheaders = {
			'Cookie':'ssic=%s' % self.__ssic,
		    'Content-Type':'application/oct-stream',
		    'Pragma':'xz4BBcV%s' % self.__guid,
			}
	    
	def register(self):
		response = ""
		for step in range(1,3):
			self.__construct_request('REG', step, response)
			response = self.__send_request()
	
	#type is ethier mobile/who=mobile_num or fetion/who=fetion_num
	def add_buddy(self, type, who):
		self.__construct_request('AddBuddy', type, who)
		return self.__send_request()
	
	def get_contact_list(self):
		self.__construct_request('GetContactList')
		return self.__send_request()

	def get_contact_info(self, uri):
		self.__construct_request('GetContactsInfo', ret=uri)
		return self.__send_request()

	def send_sms(self, to, sms, type='SENDSMS'):
		self.__construct_request(type, arg=to, ret=sms)
		self.__send_request()

	def __construct_request(self, cmd, arg = "", ret="", extra=""):
		body = ''
		if cmd == 'REG':
			body = FetionLoginXML
			self.__init_request('R')
			if arg == 1: #unauthorized
				pass
			elif arg == 2: #authorized
				nonce = re.search('nonce="(.*)"', ret).group(1) # nonce from server
				cnonce = self.__get_cnonce() #nonce from client
				response = self.__get_response_sha1(nonce, cnonce)
				salt = self.__get_salt()
				d_print(SIPC_V2.TAG, ('nonce', 'cnonce', 'response', 'salt'), locals())
				self.__header.insert(3, ('A', 'Digest algorithm="SHA1-sess",response="%s",cnonce="%s",salt="%s"' % (response, cnonce,salt)))
			else:
				pass
		elif cmd == 'AddBuddy':
			self.__init_request('S')
			self.__header.insert(3, ('N', cmd))
			if arg == 'mobile':
			    body = '<args><contacts><buddies><buddy uri="tel:%s" buddy-lists="%s" desc="Peter" expose-mobile-no="1" expose-name="1" /></buddies></contacts></args>' %(ret, SIPC_V2.STOCK_BUDDY_LIST)
			elif arg == 'fetion':
				pass #TODO: addBuddy by fetion number
		elif cmd == 'GetContactList':
			self.__init_request('S')
			self.__header.insert(3, ('N', cmd))
			body = '<args><contacts attributes="all"><buddies attributes="all" /></contacts></args>'
		
		elif cmd == 'GetContactsInfo':
			self.__init_request('S')
			self.__header.insert(3, ('N', cmd))
			body = '<args><contacts attributes="all"><contact uri="%s" /></contacts></args>' % ret

		elif cmd == 'SENDCatSMS':
			self.__init_request('M')
			self.__header.append(('T', arg))
			self.__header.append(('N', 'SendCatSMS'))
			body = ret # body now is sms
		
		self.__header.append(('L', len(body)))
		for k in self.__header:
			self.__content = self.__content + k[0] + ': ' + str(k[1]) + '\r\n'
		self.__content += '\r\n'
		self.__content += body
		self.__content += FetionSIPP
		return self.__content
	
	def __send_request(self):
		request = self.__content
		d_print(SIPC_V2.TAG, ('request',), locals())
		if self.__seq == 1:
			t = 'i'
		else:
			t = 's'

		url = self.__http_tunnel + "?t=%s&i=%s" % (t, self.__seq) #url encode should be done
		#print url, request
		response = http_send(url, request, self.__exheaders).read()
		d_print(SIPC_V2.TAG, ('response',), locals())
		self.__seq += 1
		response = self.__sendSIPP()
        # do twice if response is 'SIPP'
		if response == FetionSIPP:
			response = self.__sendSIPP()
		
		return response
	
	def __sendSIPP(self):
		body = FetionSIPP
		url = self.__http_tunnel + "?t=s&i=%s" % self.__seq
		response = http_send(url, body, self.__exheaders).read()
		d_print(SIPC_V2.TAG, ('response',), locals())
		self.__seq += 1
		return response
	
	def __init_request(self, type):
		self.__content = '%s %s %s\r\n' % (type, self.__domain, SIPC_V2.ver)
		self.__header = [('F', self.__sid), ('I', SIPC_V2.ID), ('Q', '1 %s' % type),]
	
	def __get_cnonce(self):
		return md5(str(uuid1())).hexdigest().upper()

	def __get_response_sha1(self, nonce, cnonce):
		hash_passwd = self.__hash_passwd()
		hash_passwd_str = binascii.unhexlify(hash_passwd[8:])
		key = sha1("%s:%s:%s" % (self.__sid, self.__domain, hash_passwd_str)).digest()
		h1 = md5("%s:%s:%s" % (key,nonce,cnonce)).hexdigest().upper()
		h2 = md5("REGISTER:%s" % self.__sid).hexdigest().upper()
		response = md5('%s:%s:%s' % (h1, nonce, h2)).hexdigest().upper()
		return response

	def __get_salt(self):
		return self.__hash_passwd()[:8]

	def __hash_passwd(self):
		salt = 'wzm\x03'
		src =  salt + sha1(self.__passwd).digest()
		return "777A6D03" + sha1(src).hexdigest().upper()

if __name__ == '__main__':
	sipc = SIPC_V2('793401629', 'fetion.com.cn', 'sj19840615', 'HTTP://221.130.44.193/ht/sd.aspx', 'ssic', 'proxy')
